package com.skstudio.nuprint.view;

import java.io.File;

import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.GestureDetector;
import android.view.GestureDetector.OnGestureListener;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.ScaleGestureDetector.OnScaleGestureListener;
import android.view.View;

public class PostScriptPageView extends View implements OnGestureListener, OnScaleGestureListener, PsParser.ParserEventListener {

	final static float cMaxScale = 1.0f;
	
	float mMinScale = 1.0f;
	
	GestureDetector mDetector = null;
	
	ScaleGestureDetector mScaleDetector = null;
	
	Paint mPaint;
	
	Bitmap mRimBitmap = null;
	
	void setupView() {
		mDetector = new GestureDetector(getContext(), this);
		mScaleDetector = new ScaleGestureDetector(getContext(), this);
		mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
	}
	
	public PostScriptPageView(Context context) {
		super(context);
		setupView();
	}

	public PostScriptPageView(Context context, AttributeSet attrs) {
		super(context, attrs);
		setupView();
	}
	
	public PostScriptPageView(Context context, AttributeSet attrs, int defStyle) {
		super(context, attrs, defStyle);
		setupView();
	}
	
	PsParser mParser = null;
	
	public void setFile(File file) {
		mParser = new PsParser(getContext(), this);
		mParser.openFile(file);
	}
	
	public void close() {
		mParser.closeFile();
	}
	
	@SuppressLint("DrawAllocation")
	@Override
	public void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		
		if (mBitmap == null) return;
		
		if (mScale == 0.0f) {
			//try best fit on screen
			float bmWidth = mBitmap.getWidth();
			float bmHeight= mBitmap.getHeight();
			
			float viewWidth = getWidth();
			float viewHeight = getHeight();
			
			float xScale = viewWidth / bmWidth;
			float yScale = viewHeight / bmHeight;
			
			mScale = Math.min(Math.min(xScale, yScale), cMaxScale);
			mMinScale = mScale;
		} 

		Matrix mat = new Matrix();
		mat.setScale(mScale, mScale);
		mat.postTranslate(mLeft, mTop);
		canvas.drawBitmap(mBitmap, mat, null);
	}
	
	Bitmap mBitmap = null;
	
	float mScale = 0.0f;
	
	float mLeft = 0, mTop = 0;
	
	public boolean onTouchEvent(MotionEvent event) {
		return mDetector.onTouchEvent(event) || mScaleDetector.onTouchEvent(event);
	}
	
	@Override
	public boolean onDown(MotionEvent arg0) {
		return true;
	}
	
	@Override
	public boolean onFling(MotionEvent arg0, MotionEvent arg1, float arg2,
			float arg3) {
		return false;
	}
	
	@Override
	public void onLongPress(MotionEvent arg0) {
	}
	
	@Override
	public boolean onScroll(MotionEvent arg0, MotionEvent arg1, float arg2,
			float arg3) {
		int viewWidth = getWidth();
		int viewHeight = getHeight();
		int imWidth = (int) (mBitmap.getWidth() * mScale);
		int imHeight = (int) (mBitmap.getHeight() * mScale);
		
		float newLeft = mLeft, newTop = mTop;
		if ((viewWidth < imWidth) && (mLeft - arg2 < 0) && ((mLeft - arg2 - viewWidth) > -1 * imWidth)) {
			newLeft -= arg2;
		}
		if (viewHeight < imHeight && (mTop - arg3 < 0) && ((mTop - arg3 - viewHeight) > -1 * imHeight)) {
			newTop -= arg3;
		}
		
		if ((newLeft - viewWidth) < -1 * imWidth) newLeft = -1 * imWidth + viewWidth;
		if (newLeft > 0) newLeft = 0;
		if ((newTop - viewHeight) < -1 * imHeight) newTop = -1 * imHeight + viewHeight;
		if (newTop > 0) newTop = 0;
		
		if (mLeft != newLeft || mTop != newTop) 
			invalidate();
		mLeft = newLeft; mTop = newTop;
		
		return true;
	}
	
	@Override
	public void onShowPress(MotionEvent arg0) {
	}
	
	@Override
	public boolean onSingleTapUp(MotionEvent arg0) {
		if (!mFileLoaded) return false;
		
		if (arg0.getX() < getWidth() / 2) {
			if (mCurrentPage > 0)
				mCurrentPage--;
			else 
				return true;
		} else {
			if (mCurrentPage + 1 < mParser.getPageCount())
				mCurrentPage++;
			else 
				return true;
		}
			
		mParser.renderPage(mCurrentPage);
		return true;
	}

	@Override
	public boolean onScale(ScaleGestureDetector arg0) {
		float newScale = mScale;
		newScale *= arg0.getScaleFactor();
		
		if (cMaxScale < newScale)
			newScale = cMaxScale;
		if (mMinScale > newScale)
			newScale = mMinScale;
		
		if (newScale == mScale)
			return true;
		
		mScale = newScale;
		onScroll(null, null, 0, 0); 
		invalidate();
		
		return true;
	}

	@Override
	public boolean onScaleBegin(ScaleGestureDetector arg0) {
		return true;
	}

	@Override
	public void onScaleEnd(ScaleGestureDetector arg0) {
	}

	boolean mFileLoaded = false;
	
	long mCurrentPage = 0;
	
	@Override
	public void onFileLoaded() {
		mParser.renderPage(mCurrentPage);
		mFileLoaded = true;
	}

	@Override
	public void onPageRendered(int pageNo, Bitmap bmp) {
		if (mBitmap != null) {
			mBitmap.recycle();
		}
		
		mBitmap = bmp;
		invalidate();
	}
}
